package com.hyuk.hyukfgw.listener;

import com.hyuk.hyukfgw.service.ops.bean.OpsChangeMsg;
import com.hyuk.hyukfgw.util.excp.FgwCodeEnum;
import com.hyuk.hyukfgw.util.excp.FgwException;
import com.hyuk.hyukfgw.util.json.JacksonUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.List;

@Slf4j
public abstract class AbstractOpsChangeExecutor implements OpsChangeExecutor {
    
    protected abstract Object getInstance(String className);
    
    @Override
    public Object execute(OpsChangeMsg opsChangeMsg) {
        // 1. get instance
        Object instance = getInstance(opsChangeMsg.getClassName());
        
        // 2. 获取参数类型
        Class<?>[] parametersTypes = getParameterTypes(opsChangeMsg);
        
        // 3、 获取执行方法
        Method method = getMethod(opsChangeMsg, parametersTypes, instance);
        
        // 4. 构建参数
        Object[] args = getArgs(opsChangeMsg, parametersTypes);
        
        // 5. 反射调用
        return invoke(method, instance, args);
    }
    
    private Object invoke(Method method, Object instance, Object[] args) {
        try {
            return method.invoke(instance, args);
        } catch (Exception e) {
            log.warn("[AbstractOpsChangeExecutor][invoke] 出现异常", e);
            throw new FgwException(FgwCodeEnum.ARGS_ERROR);
        }
    }
    
    private Object[] getArgs(OpsChangeMsg opsChangeMsg, Class<?>[] parametersTypes) {
        List<Object> parameterValueList = opsChangeMsg.getParametersValueList();
        if (parameterValueList == null || parameterValueList.isEmpty()) {
            return new Object[0];
        }
        
        // 这里参数如果是对象, 默认会转成 LinkedHashMap, 需要处理一下
        Object[] args = new Object[parameterValueList.size()];
        for (int i = 0; i < parameterValueList.size(); i++) {
            args[i] = JacksonUtils.fromJson(JacksonUtils.toJson(parameterValueList.get(i)), parametersTypes[i]);
        }
        return args;
    }
    
    private Method getMethod(OpsChangeMsg opsChangeMsg, Class<?>[] parametersTypes, Object instance) {
        try {
            return instance.getClass().getMethod(opsChangeMsg.getMethodName(), parametersTypes);
        } catch (NoSuchMethodException e) {
            log.warn("[AbstractOpsChangeExecutor][getMethod] 出现异常, className : {}, methodName : {}",
                    opsChangeMsg.getClassName(), opsChangeMsg.getMethodName(), e);
            throw new FgwException(FgwCodeEnum.ARGS_ERROR);
        }
    }
    
    /**
     * 获取参数类型
     *
     * @param opsChangeMsg
     * @return
     */
    private Class<?>[] getParameterTypes(OpsChangeMsg opsChangeMsg) {
        List<String> parametersTypeList = opsChangeMsg.getParametersTypeList();
        // 没有参数
        if (parametersTypeList == null || parametersTypeList.isEmpty()) { return new Class[0]; }
        
        // 开始遍历构建参数类型
        Class<?>[] parametersTypes = new Class[parametersTypeList.size()];
        try {
            for (int i = 0; i < parametersTypeList.size(); i++) {
                parametersTypes[i] = Class.forName(parametersTypeList.get(i));
            }
        } catch (ClassNotFoundException classNotFoundException) {
            log.warn("[AbstractOpsChangeExecutor][getParameterTypes] 出现异常, className : {}, methodName : {}",
                    opsChangeMsg.getClassName(), opsChangeMsg.getMethodName(), classNotFoundException);
            throw new FgwException(FgwCodeEnum.ARGS_ERROR);
        }
        return parametersTypes;
    }
}
